package MyGui;

import java.awt.*;
import java.awt.event.*;
import java.lang.Integer;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.util.*;
import java.text.*;

import Element.*;
import Element.Geom.*;
import DistSys.*;

/**
 * The class <code>DataSumDlg</code> implements the data summary dialog.
 *
 */
public class DataSumDlg extends MyDlgFrame implements ActionListener,
                                                      ListSelectionListener {
    private final static int AREA = 0;
    private final static int ELEM = 1;
    private final static int COUNT = 2;

    /* Dialog items */
    private ZoneComboBox comboZone;
    private SumTableModel[] modelSum = new SumTableModel[COUNT];
    private JTable[] tblSum = new JTable[COUNT];

    /* The "display memory" */
    private class Data implements Comparable {
        int iCount;
        String sType;
        int iType;
        public int compareTo(Object o) { return (((Data)o).iCount - iCount); }
    }
    private Data[][] aaSum = new Data[COUNT][];
    private int[] aiTemplCount;
    private int[] aiTemplType; // indicating which types a template belongs
                               // associated with aiTemplCount[]

    /**
      * Creates a <code>DataSumDlg</code>.
      */
    public DataSumDlg(MainFrame parent, String title) {
        super(parent, title);
        setSize(300,400);
        Container contentPane = getContentPane();
        contentPane.setLayout(gridBagLayout);

        aaSum[AREA] = null;
        aaSum[ELEM] = null;

        // Initialize components
        comboZone = new ZoneComboBox();
        comboZone.addActionListener(this);
        JLabel lblZone = new JLabel("Area:");
        lblZone.setDisplayedMnemonic('A');
        lblZone.setLabelFor(comboZone);

        for (int i = 0; i < COUNT; i++) {
            modelSum[i] = new SumTableModel(i);
            tblSum[i] = new JTable(modelSum[i]);
            tblSum[i].setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
            tblSum[i].getColumnModel().getColumn(0).setPreferredWidth(50);
            tblSum[i].getColumnModel().getColumn(1).setPreferredWidth(250);
            tblSum[i].setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            tblSum[i].setShowGrid(false);
            tblSum[i].getTableHeader().setReorderingAllowed(false);
        }
        tblSum[AREA].getSelectionModel().addListSelectionListener(this);
        JLabel lblAreaSum = new JLabel("Area Summary:");
        lblAreaSum.setDisplayedMnemonic('S');
        lblAreaSum.setLabelFor(tblSum[AREA]);

        JLabel lblElemSum = new JLabel("Component Breakdown:");
        lblElemSum.setDisplayedMnemonic('C');
        lblElemSum.setLabelFor(tblSum[ELEM]);

        // Construct panel
        add(contentPane, lblZone, 0, 0, 1, 1, 0, 0,
            GridBagConstraints.EAST, GridBagConstraints.NONE, GAP, GAP, 0, 0);
        add(contentPane, comboZone, 1, 0, 1, 1, 100, 0,
            GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
            GAP, GAP, 0, GAP);

        add(contentPane, lblAreaSum, 0, 1, 2, 1, 0, 0,
            GridBagConstraints.SOUTHWEST, GridBagConstraints.NONE,
            GAP, GAP, 0, GAP);
        add(contentPane, new JScrollPane(tblSum[0]), 0, 2, 2, 1, 100, 100,
            GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH,
            0, GAP, 0, GAP);

        add(contentPane, lblElemSum, 0, 3, 2, 1, 0, 0,
            GridBagConstraints.SOUTHWEST, GridBagConstraints.NONE,
            GAP, GAP, 0, GAP);
        add(contentPane, new JScrollPane(tblSum[1]), 0, 4, 2, 1, 100, 100,
            GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH,
            0, GAP, GAP, GAP);

        addWindowListener(new WindowAdapter() {
            public void windowActivated(WindowEvent evt) { updateAreaSum(); }
        });
    }

    /*
     * Table model for both summaries
     */
    private class SumTableModel extends AbstractTableModel {
        private int iSum;
        public SumTableModel(int iSum) { this.iSum = iSum; }
        public int getRowCount() {
            return (aaSum[iSum] != null ? aaSum[iSum].length : 0);
        }
        public int getColumnCount() { return 2; }
        public String getColumnName(int col) { return ""; }
        public Object getValueAt(int row, int col) {
            if (aaSum[iSum][row] == null) return "";
            else if (col == 0) return new Integer(aaSum[iSum][row].iCount);
            else return aaSum[iSum][row].sType;
        }
        public Class getColumnClass(int col) {
            return (col == 0 ? Number.class : String.class);
        }
    };

    /**
     * This method is public as an implementation side effect.
     * do not call or override.
     */
    public void actionPerformed(ActionEvent evt) {
        // comboArea is the only possible source.
        updateAreaSum();
    }

    /*
     * Updates the area summary based on the selected zone.
     */
    private void updateAreaSum() {
        double dZone;
        try {
            dZone = comboZone.getSelectedZone();
        } catch(ZoneComboBox.ZoneException e) {
            aaSum[AREA] = null;
            modelSum[AREA].fireTableDataChanged();
            return;
        }

        // get data
        double dLineLength = 0.0;
        double dCableLength = 0.0;
        double dTotalCust = 0.0;
        double dTotalKVA = 0.0;
        int[] aiTypeCount = new int[SysConst.MAX_TYPE];
        aiTemplCount = new int[Templates.allList.size()];    // auto assigned to 0;
        aiTemplType  = new int[Templates.allList.size()];    // auto assigned to 0;

        for (int i = 0; i < Sys.elemList.size(); i++) {
            AbsElem elem = (AbsElem)Sys.elemList.elementAt(i);
            AbsElemGeom geom = elem.getElemGeomObj();

            if (!Zone.getZoneFits(dZone, elem))
                continue;

            AbsElem dftTemp = elem.getDftTemp();
            if (dftTemp != null) {
                for (int templ = 0; templ < Templates.allList.size(); templ++) {
                    if (dftTemp.equals(Templates.allList.elementAt(templ))){
                        int type = elem.getType();
                        aiTemplCount[templ]++;
                        if (aiTemplType[templ] == 0)
                            aiTemplType[templ] = type;

                        aiTypeCount[type]++;
                        if (type == SysConst.TYPE_CABLE)
                            dCableLength += elem.getData(AbsElem.DATA_LENGTH);
                        else if (type == SysConst.TYPE_LINE)
                            dLineLength += elem.getData(AbsElem.DATA_LENGTH);
                        else if (type == SysConst.TYPE_LOAD) {
                            dTotalCust += elem.getData(AbsElem.DATA_CUSTOMERS);
                            dTotalKVA += elem.getData(AbsElem.DATA_CONST_POWER);
                        }

                        break; // break inner loop
                    }
                } // inner for loop
            }
        } // outer for loop

        for (int type = SysConst.TYPE_NONE+1; type < SysConst.MAX_TYPE; type++)
            aiTypeCount[0] += aiTypeCount[type];

        // format data
        if (aaSum[AREA] == null) {
            aaSum[AREA] = new Data[SysConst.ssType.length];
            aaSum[AREA][0] = new Data();
            aaSum[AREA][0].sType = "Components";
        }
        String sUnit = " " + SysConst.unitStrings[Sys.prjInfo.unitOfLength]+")";
        NumberFormat num = NumberFormat.getNumberInstance();

        aaSum[AREA][0].iCount = aiTypeCount[0];
        for (int i = 2; i < SysConst.ssType.length; i++) {
            Data data = aaSum[AREA][i] = new Data();
            data.iType = SysConst.mapIndexToType(i);
            data.iCount = aiTypeCount[data.iType];
            data.sType = SysConst.ssType[i];
            switch (data.iType) {
                case SysConst.TYPE_LINE:
                    num.setMaximumFractionDigits(
                        SysConst.unitFracDigits[Sys.prjInfo.unitOfLength]);
                    data.sType += " (" + num.format(dLineLength) + sUnit;
                    break;
                case SysConst.TYPE_CABLE:
                    num.setMaximumFractionDigits(
                        SysConst.unitFracDigits[Sys.prjInfo.unitOfLength]);
                    data.sType += " (" + num.format(dCableLength) + sUnit;
                    break;
                case SysConst.TYPE_LOAD:
                    num.setMaximumFractionDigits(0);
                    data.sType += " (" + num.format(dTotalCust) + " Customer; "+
                                  num.format(dTotalKVA) + " kVA)";
                    break;
            }
        }

        // sort data
        Arrays.sort(aaSum[AREA], 2, aaSum[AREA].length);

        // display data
        modelSum[AREA].fireTableDataChanged();
        tblSum[AREA].getSelectionModel().setSelectionInterval(0, 0);
    }

    /**
     * This method is public as an implementation side effect.
     * do not call or override.
     */
    public void valueChanged(ListSelectionEvent evt) {
        // tblSum[AREA] is the only possible source.
        if (!evt.getValueIsAdjusting()) {
            int iRow = tblSum[AREA].getSelectedRow();
            if (iRow >= 0 && aaSum[AREA][iRow] != null) { //skip the blank line
                updateElemSum(aaSum[AREA][iRow].iType);
            }
        }
    }

    /*
     * Updates the component breakdown based on the selected zone and template.
     */
    private void updateElemSum(int iType) {
        if (iType == SysConst.TYPE_NONE) { return; } //preventive code

        double dZone;
        try {
            dZone = comboZone.getSelectedZone();
        } catch(ZoneComboBox.ZoneException e) {
            aaSum[ELEM] = null;
            modelSum[ELEM].fireTableDataChanged();
            return;
        }
        aiTemplCount = new int[Templates.allList.size()];    // auto assigned to 0;
        aiTemplType  = new int[Templates.allList.size()];    // auto assigned to 0;

        for (int i = 0; i < Sys.elemList.size(); i++) {
            AbsElem elem = (AbsElem)Sys.elemList.elementAt(i);

            if (!Zone.getZoneFits(dZone, elem)) { continue; }
            if ( iType != SysConst.TYPE_ALL && iType != elem.getType() ) {continue;}

            AbsElem dftTemp = elem.getDftTemp();
            if (dftTemp != null) {
                for (int templ = 0; templ < Templates.allList.size(); templ++) {
                    if (dftTemp.equals(Templates.allList.elementAt(templ))){
                        int type = elem.getType();
                        aiTemplCount[templ]++;
                        break; // break inner loop
                    }
                } // inner for loop
            }
        } // outer for loop

        int iCount=0;
        for( int i=0; i< aiTemplCount.length; i++){
            if (aiTemplCount[i] != 0) { iCount++; }
        }

        aaSum[ELEM] = new Data[iCount];
        iCount=0;
        for(int i=0; i< aiTemplCount.length; i++){
            if( aiTemplCount[i] !=0 ){
                Data data = aaSum[ELEM][iCount] = new Data();
                data.iCount = aiTemplCount[i];
                data.sType = ((AbsElem)Templates.allList.get(i)).getElemGeomObj().getName();
                iCount ++;
            }
        }
        // sort data
        Arrays.sort(aaSum[ELEM]);
        // display data
        modelSum[ELEM].fireTableDataChanged();
    }

    /**
     * There is a bug in this code. But this approach is more effeciency.
     * It may be modified in the future.
     */
//    private void updateElemSum(int iType) {
//        if (iType == SysConst.TYPE_ALL || iType > SysConst.TYPE_NONE) {
//            // get count
//            int iCount = 0;
//            for (int i = 0; i < Templates.allList.size(); i++) {
//                if (aiTemplType[i] != 0 &&
//                    (iType == SysConst.TYPE_ALL || iType == aiTemplType[i]))
//                    iCount++;
//            }
//
//            // get data
//            aaSum[ELEM] = new Data[iCount];
//            iCount = 0;
//            for (int i = 0; i < Templates.allList.size(); i++) {
//                if (aiTemplType[i] != 0 &&
//                    (iType == SysConst.TYPE_ALL || iType == aiTemplType[i])) {
//                    Data data = aaSum[ELEM][iCount] = new Data();
//                    data.iCount = aiTemplCount[i];
//                    data.sType = ((AbsElem)Templates.allList.elementAt(i)).
//                        getElemGeomObj().getName();
//                    iCount++;
//                }
//            }
//        } else // the second line is a dummy line
//            aaSum[ELEM] = null;
//
//        // sort data
//        Arrays.sort(aaSum[ELEM]);
//
//        // display data
//        modelSum[ELEM].fireTableDataChanged();
//    }
}
